package pv.map;

import android.app.Activity;
import android.content.Context;
import android.graphics.Bitmap;
import android.location.Location;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.TextView;

import com.google.android.gms.common.GooglePlayServicesNotAvailableException;
import com.google.android.gms.maps.CameraUpdateFactory;
import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.GoogleMap.OnMarkerClickListener;
import com.google.android.gms.maps.MapView;
import com.google.android.gms.maps.MapsInitializer;
import com.google.android.gms.maps.UiSettings;
import com.google.android.gms.maps.model.BitmapDescriptor;
import com.google.android.gms.maps.model.BitmapDescriptorFactory;
import com.google.android.gms.maps.model.CameraPosition;
import com.google.android.gms.maps.model.LatLng;
import com.google.android.gms.maps.model.Marker;
import com.google.android.gms.maps.model.MarkerOptions;
import com.google.android.gms.maps.model.Polyline;
import com.google.android.gms.maps.model.PolylineOptions;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import java.io.IOException;
import java.util.List;

import pv.finder.R;
import pv.network.BaseAsyncTask;
import pv.util.ImageHelper;
import pv.util.Utility;

public class MapHelper {
    public static final String CANT_GET_DIRECTION = "Can't find their way in the present time, Please try again";
    public static final String MODE_DRIVING = "&mode=driving";
    public static final String MODE_WALKING = "&mode=walking";
    public static final String MODE_BICYCLING = "&mode=bicycling";
    public static final String MODE_TRANIT = "&mode=transit";
    public static final String CANT_GETTING_DIRECTION = "Getting driving directions";
    public static final String NO_ROUTE_FOUND = "No rout found";
    public static final int MAP_DEFAULT_ZOOM_LEVEL = 15;
    public static final int MAP_DEFAULT_TILT = 0;
    public static final int MAP_DEFAULT_ORIENTATION = 0;
    public static final int MAP_TIME_UPDATE = 1000 * 15;
    public static final int MAP_DISTANCE_UPDATE = 5;
    public static final double MAP_DEFAULT_LATITUDE = 10.991621;
    public static final double MAP_DEFAULT_LONGITUDE = 106.897127;
    public static final int WIDTH_IMAGE_MARKER = 75;
    public static final int HEIGHT_IMAGE_MARKER = 75;
    public static final String URL_GETDIRECTION_1 = "http://maps.googleapis.com/maps/api/directions/json?";
    public static final String URL_GETDIRECTION_2 = "&waypoints=optimize:true&sensor=false";
    Context context;
    GoogleMap map;
    MapView mapView;
    TextView tv;
    LocationHelper locationHelper;
    private Polyline polyline;

    public MapHelper(Context context, GoogleMap map) {
        locationHelper = LocationHelper.getInstance();
        locationHelper.init(context);
        this.context = context;
        this.map = map;

    }

    public MapHelper(Context context) {
        locationHelper = LocationHelper.getInstance();
        locationHelper.init(context);
        this.context = context;

    }

    public MapHelper(Context context, MapView mapView) {
        locationHelper = LocationHelper.getInstance();
        locationHelper.init(context);
        this.context = context;
        this.mapView = mapView;

    }

    public MapView getMapView() {
        return mapView;
    }

    public void setMapView(MapView mapView) {
        this.mapView = mapView;
    }

    public GoogleMap getMap() {
        return map;
    }

    public void setMap(GoogleMap map) {
        this.map = map;
    }

    private void setUpMapIfNeeded() {

        if (map == null) {

            map = mapView == null ? null : ((MapView) mapView).getMap();
        }
        if (map != null) {
            // map.setOnMapClickListener(this);
            map.setMyLocationEnabled(true);

            UiSettings uiSetting = map.getUiSettings();
            uiSetting.setZoomControlsEnabled(false);
            uiSetting.setMyLocationButtonEnabled(false);


            // route(FROM, TO);

        }
    }

    public LocationHelper getLocationHelper() {
        return locationHelper;
    }

    public void setLocationHelper(LocationHelper locationHelper) {
        this.locationHelper = locationHelper;
    }

    public Marker addMarker(LatLng latLng, String title, String snippet) {
        return map == null ? null : map.addMarker(new MarkerOptions()
                .position(latLng)
                .title(title)
                .icon(BitmapDescriptorFactory
                        .fromResource(android.R.drawable.ic_dialog_map))
                .snippet(snippet));

    }

    public Marker addMarker(String address, String title, String snippet) {

        LatLng latLng = locationHelper.getLatLngFromAddress(address);
        latLng = latLng == null ? new LatLng(MapHelper.MAP_DEFAULT_LATITUDE,
                MapHelper.MAP_DEFAULT_LONGITUDE) : latLng;
        return latLng == null ? null : addMarker(latLng, title, snippet);

    }

    public Marker addMarker(String address, String title, String snippet,
                            Bitmap bitmap, int color) {

        LatLng latLng = locationHelper.getLatLngFromAddress(address);
        latLng = latLng == null ? new LatLng(MapHelper.MAP_DEFAULT_LATITUDE,
                MapHelper.MAP_DEFAULT_LONGITUDE) : latLng;
        ImageHelper im = ImageHelper.getInstance();

        Bitmap icon = im.boderForImage(context, im.scaleImage(
                MapHelper.WIDTH_IMAGE_MARKER, MapHelper.HEIGHT_IMAGE_MARKER,
                bitmap), MapHelper.WIDTH_IMAGE_MARKER + 10,
                MapHelper.HEIGHT_IMAGE_MARKER + 10, 5, color);

        BitmapDescriptor bmd = icon == null ? BitmapDescriptorFactory
                .fromResource(android.R.drawable.btn_star)
                : BitmapDescriptorFactory.fromBitmap(icon);

        return map == null ? null : map.addMarker(new MarkerOptions()
                .position(latLng).title(title).icon(bmd).snippet(snippet));

        // TODO Auto-generated method stub

    }

    public Marker addMarker(String address, String title, String snippet,
                            Bitmap bitmap) {

        LatLng latLng = locationHelper.getLatLngFromAddress(address);
        latLng = latLng == null ? new LatLng(MapHelper.MAP_DEFAULT_LATITUDE,
                MapHelper.MAP_DEFAULT_LONGITUDE) : latLng;

        return map == null ? null : map.addMarker(new MarkerOptions()
                .position(latLng).title(title)
                .icon(BitmapDescriptorFactory.fromBitmap(bitmap))
                .snippet(snippet));

        // TODO Auto-generated method stub

    }

    public Marker addMarker(LatLng latLng, String title, String snippet,
                            Bitmap bitmap) {
        latLng = latLng == null ? new LatLng(MapHelper.MAP_DEFAULT_LATITUDE,
                MapHelper.MAP_DEFAULT_LONGITUDE) : latLng;

        return map == null ? null : map.addMarker(new MarkerOptions()
                .position(latLng).title(title)
                .icon(BitmapDescriptorFactory.fromBitmap(bitmap))
                .snippet(snippet));

        // TODO Auto-generated method stub

    }

    public String getAddressCurrentLocation() {
        return locationHelper.getAddress(getCurrentLocation());
    }

    public Location getCurrentLocation() {
        return locationHelper != null ? locationHelper.getCurrentLocation()
                : null;
    }

    public void moveTo(LatLng latLng) {
        if (map != null && latLng != null) {
            CameraPosition cameraPosition = new CameraPosition.Builder()
                    .target(latLng) // Sets the center of the map to Mountain
                            // View
                    .zoom(MapHelper.MAP_DEFAULT_ZOOM_LEVEL) // Sets the zoom
                    .bearing(MapHelper.MAP_DEFAULT_TILT) // Sets the orientation
                            // of
                            // the camera to
                            // east
                    .tilt(MapHelper.MAP_DEFAULT_TILT) // Sets the tilt of the
                            // camera
                            // to 30 degrees
                    .build(); // Creates a CameraPosition from the builder
            map.animateCamera(CameraUpdateFactory
                    .newCameraPosition(cameraPosition));
        }
    }

    public void moveTo(Location location) {

        if (location != null)
            moveTo(convertLatLngLocation(location));
    }

    public void moveToCurrent() {
        // setup();
        // locationHelper.
        moveTo(getCurrentLocation());
    }

    public void moveTo(String currentAddress) {
        // TODO Auto-generated method stub
        LatLng currentLatLng = locationHelper
                .getLatLngFromAddress(currentAddress);
        moveTo(currentLatLng);
    }

    /*
     * for map view this event to handle for mapview onCreate(Bundle) onResume()
     * onPause() onDestroy() onSaveInstanceState(Bundle) onLowMemory()
     */
    public void onCreate(Bundle arg) {
        if (mapView != null) {
            mapView.onCreate(arg);
            try {
                MapsInitializer.initialize(context);
            } catch (GooglePlayServicesNotAvailableException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }

        // locationManager = (LocationManager) context
        // .getSystemService(Context.LOCATION_SERVICE);

    }

    public void onResume() {
        if (mapView != null)
            mapView.onResume();
        if (map != null)
            map.setMyLocationEnabled(true);
        locationHelper.startListener();
    }

    public void onPause() {
        if (mapView != null)
            mapView.onPause();
        if (map != null)
            map.setMyLocationEnabled(false);
        locationHelper.removeListener();
        // locationManager.removeUpdates(listener);
    }

    public void onSaveInstanceState(Bundle bundle) {
        if (mapView != null)
            mapView.onSaveInstanceState(bundle);
    }

    public void onLowMemory() {
        if (mapView != null)
            mapView.onLowMemory();
    }

    public void onDestroy() {
        if (mapView != null)
            mapView.onDestroy();
    }

    public boolean getGPSPrviderEnable() {
        return locationHelper.isGPSPrviderEnable();/*
                                                     * locationManager.
													 * isProviderEnabled
													 * (LocationManager
													 * .GPS_PROVIDER);
													 */
    }

    public void onActivityCreated(Activity activity) {
        this.context = activity;
        setUpMapIfNeeded();
    }

    public void route(String to, String mode) {
        route(/* getAddressCurrentLocation() */getCurrentLocation().getLatitude()
                + "," + getCurrentLocation().getLongitude(), to, mode);
    }

    public void route(String from, String to, String mode) {

        new GetDirectionPoints(context, from, to, mode).execute("");

    }

    public Polyline showRoute(List<LatLng> listGeoPoint) {
        if (listGeoPoint != null) {
            PolylineOptions plo = new PolylineOptions();
            for (int i = 0; i < listGeoPoint.size(); i++) {
                plo.add(listGeoPoint.get(i));
            }
            plo.color(context.getResources().getColor(R.color.color_blue_1))
                    .width(8);
            return map.addPolyline(plo);
        }
        return null;

    }

    public LatLng convertLatLngLocation(Location location) {
        return new LatLng(location.getLatitude(), location.getLongitude());
    }

    public void setShowRouteInfo(final TextView tvRouteInfo) {
        tv = tvRouteInfo;
    }

    public void clear() {
        if (map != null) {
            map.clear();

        }
    }

    public void onMarkerListener(OnMarkerClickListener listener) {
        if (map != null)
            map.setOnMarkerClickListener(listener);
    }

    public void clearRoute() {
        if (polyline != null)
            polyline.remove();
    }

    /**
     * Async task
     */

    class GetDirectionPoints extends BaseAsyncTask {
        String from;
        String to;
        // List<GeoPoint> listGeoPoint;
        RouteInfo routeInfo;
        GetPolylineAlgorithm algorithm;
        String mode;

        public GetDirectionPoints(Context context, String from, String to) {
            super(context);
            this.from = from;
            this.to = to;
            this.mode = "";
        }

        public GetDirectionPoints(Context context, String from, String to,
                                  String mode) {
            // TODO Auto-generated constructor stub
            super(context);
            this.from = from;
            this.to = to;
            this.mode = mode;

        }

        @Override
        protected String doInBackground(String... arts) {
            try {
//                HttpClient httpclient = NetworkHelper.createHttpClient();
//
//                HttpGet httpGet = new HttpGet(new URI(getURL()));
//                httpGet.setHeader("Content-Type",
//                        "application/x-www-form-urlencoded");
//                HttpResponse response = httpclient.execute(httpGet);
//                StatusLine statusLine = response.getStatusLine();


                MyHttpGetMethod method = new MyHttpGetMethod(getURL());
                String response = method.excute();


                if (method.getResponseCode() == 200) {


                    JSONArray jsonArrayRoute = new JSONObject(
                            /*NetworkHelper.convertToString(*/response/*)*/)
                            .getJSONArray("routes");

                    if (jsonArrayRoute.length() == 0) {
                        routeInfo = new RouteInfo();
                        return CANT_GET_DIRECTION;
                    }

                    // List<GeoPoint> listGeoPoint = decodePoly(polynejson
                    // .getString("points"));
                    // routeInfo = new RouteInfo(distance, duration,
                    // listGeoPoint);
                    algorithm = new EncodingPolylineAlgorithm();
                    // algorithm = new HandMadeAlgorithm();
                    routeInfo = algorithm.encoding(jsonArrayRoute);
                    return context.getString(R.string.TASK_SUCCESS);
                }
                return context.getString(R.string.TASK_ERROR_COMMON);
            } catch (IOException e) {
                Utility.LogE(this.getClass(), e);
                return context.getString(R.string.TASK_ERROR_NETWORK);
            } catch (JSONException e) {
                Utility.LogE(this.getClass(), e);
                return context.getString(R.string.TASK_ERROR_COMMON);

            } catch (NullPointerException e) {
                // TODO: handle exception
                Utility.LogE(this.getClass(), e);
                return context.getString(R.string.TASK_ERROR_COMMON);
            }
        }

        protected String getURL() {
            // TODO Auto-generated method stub
            return MapHelper.URL_GETDIRECTION_1 + "origin="
                    + from.replace(" ", "%20") + "&destination="
                    + to.replace(" ", "%20") + MapHelper.URL_GETDIRECTION_2
                    + mode;
        }

        // protected String getEntry() {
        // // TODO Auto-generated method stub
        //
        // return "origin=" + start.replace(" ", "%20") + "&destination="
        // + end.replace(" ", "%20");
        // }

        protected void onPreExecute() {
            super.onPreExecute();
            Log.i("unit test", "show dialog");
            // dialog.showBox(MapHelper.CANT_GETTING_DIRECTION);
            // listStores = new ArrayList<Stores>();
            if (polyline != null)
                polyline.remove();
        }

        @Override
        protected void doIfSuccess() {
            if (routeInfo != null) {

                if (Float.valueOf(routeInfo.getDistance().replace(" km", "")
                        .replace(",", "")) <= 250) {
                    polyline = showRoute(routeInfo.getListLatLng());
                    if (tv != null) {
                        tv.setVisibility(View.VISIBLE);
                        tv.setText(String.valueOf("To address:" + to
                                + ", Distance:" + routeInfo.getDistance()
                                + ", Duration:" + routeInfo.getDuration()));
                    }
                } else {
                    Utility.showMessage(context, MapHelper.NO_ROUTE_FOUND);

                }

            }
        }

        @Override
        protected void doIfErrorCommon() {
            Utility.showMessage(context, MapHelper.CANT_GET_DIRECTION
            /* context.getResources().getString(R.string.msg_common) */);
        }

        @Override
        protected void doIfErrorNetwork() {
            Utility.showMessage(context,
                    context.getString(R.string.MSG_ERROR_NETWORK));
        }

        @Override
        protected void doIfReceiverFromServer(String receiver) {
            Utility.showMessage(context, receiver);
        }
    }
}
